
 
 
import { CreepAbilityHelper } from "utils/creep/CreepAbilityHelper";
import { APollingTask, CacheData } from "../../PollingStation";
import { BodySetup } from "utils/creep/CreepSetup";
 
import { UtilsHelper } from "utils/position/UtilsHelper";
import { WhiteListManager } from "GameLoop/WorldState/EngineConfig/WhiteListManager";
import { PositionHelper } from "utils/position/PositionHelper";
import { cpu_used } from "utils/decorate/decorate";
 

export class CacheDataHostiles<T extends ICacheHostileCreep=ICacheHostileCreep> extends CacheData<T>
{
    // private structureTypeMap:Record<string,ICacheHostileCreep[]>={};
    // private towerDamage:number[][]=[];
    // id->range:attack
    private _hostileCreepAbilitys:Record<string,Record<number,number>>={};

    // 缓存爬虫的伤害地图
    private _hostilePossibleDamageMap:Record<number,Record<number,number>>={};
    // 缓存爬虫的Mass伤害地图
    private _hostileMassDamageMap:Record<number,Record<number,number>>={};

    private _exist_foe={
        exist:false,
        Aggression:false,
    };
    public _friendCache:T[]=[]
    public damage_sum:number=0;
    public heal_max:number=0;   // 最大治疗量 估算
    constructor(data:T[])
    {
        super(data);
    }
    public get  hostileCreepAbility()
    {
        return this._hostileCreepAbilitys
    }
    /**
     * 进程
    */
    public get hostileDamageMap()
    {
        return this._hostilePossibleDamageMap;
    }
    /**
     * 远程
    */
    public get hostileMassDamageMap()
    {
        return this._hostilePossibleDamageMap;
    }
    public inquirePossibleDamage(pos:IFVector2)
    {
        if(this._hostilePossibleDamageMap[pos.x] && this._hostilePossibleDamageMap[pos.x][pos.y])
        {
            return this._hostilePossibleDamageMap[pos.x][pos.y]
        }
        return 0;
    }
    public inquireMassDamage(pos:IFVector2)
    {
        if(this._hostileMassDamageMap[pos.x] && this._hostileMassDamageMap[pos.x][pos.y])
        {
            return this._hostileMassDamageMap[pos.x][pos.y]
        }
        return 0;
    }
    public updateHostileAbilityRecord(creeps:Creep[],Nonggressivenesscreeps:Creep[])
    {
        this._hostilePossibleDamageMap={};
        this._hostileMassDamageMap={};
        this.damage_sum = 0;
        this.heal_max = 0;
        const damagerecord = this.getHostileCreepDamage(creeps);
        Memory.Debug[`爬虫伤害缓存 `]=damagerecord;
        this.setNonggressiveness(Nonggressivenesscreeps,damagerecord)
        this._hostileCreepAbilitys=damagerecord;

    }
    /**
     *
     * @param pos box min max
     * @param range 从box延伸范围
     * @param filter
     * @returns
     */
    public findInRange(pos:IRoomPosition[],range:number,filter:(creep:Creep)=>boolean)
    {
        const min_x = _.min(pos,e=>e.x).x;
        const min_y = _.min(pos,e=>e.y).y;
        const max_x = _.max(pos,e=>e.x).x;
        const max_y = _.max(pos,e=>e.y).y;
        const top = Math.max(0,min_y-range);
        const left = Math.max(0,min_x-range);
        const right = Math.min(49,max_x+range);
        const bottom = Math.min(49,max_y+range);

        const ret = Game.rooms[pos[0].roomName].lookForAtArea(LOOK_CREEPS,top,left,bottom,right,true);

        const result:Creep[]=[];
        for(const e of ret)
        {
            if(filter(e.creep))
            {
                continue;
            }
            result.push(e.creep);
        }
        return result;
    }
    /**
     * 设置没有攻击力的爬
     * @param creeps
     * @param damages_record
     */
    private setNonggressiveness(creeps:Creep[],damages_record:Record<string,Record<number,number>>)
    {
        for(const e of creeps)
        {
            damages_record[e.id]={1:0,3:0};
        }
    }
     /**
     * 计算某个房间的creep 的伤害地图
     * @param creeps 这是存在的且不在孵化的且不是NPC且含有攻击body的
     */
      private getHostileCreepDamage(creeps:Creep[])
    {
        const damages_record:Record<string,Record<number,number>>={};
        if(creeps.length ==0)
        {
            return damages_record;
        }
        const _roomName=creeps[0].pos.roomName;
        const cachestrusture =global.world.PollStructure(_roomName);
        if(cachestrusture && Game.rooms[_roomName].controller && Game.rooms[_roomName].controller!.owner && !Game.rooms[_roomName].IsMy())
        {

            for(const e of creeps)
            {
                const res =cachestrusture.lookStructure(STRUCTURE_RAMPART,e.pos);
                if(res)
                {
                    const val1 = CreepAbilityHelper.getCreepAttackAbility(e,false);
                    const val2 = CreepAbilityHelper.getCreepRangeAttackAbility(e,false);
                    this.setDamageRecord(
                        e,
                        {
                            1:Math.max(val1,val2),
                            3:val2
                        },
                        damages_record
                    )
                }
                else
                {
                    const val1 = CreepAbilityHelper.getCreepAttackAbility(e);
                    const val2 = CreepAbilityHelper.getCreepRangeAttackAbility(e);
                    this.setDamageRecord(
                        e,
                        {
                            1:Math.max(val1,val2),
                            3:val2
                        },
                        damages_record
                    )
                }

            }

        }
        else
        {
            for(const e of creeps)
            {
                const val1 = CreepAbilityHelper.getCreepAttackAbility(e);
                const val2 = CreepAbilityHelper.getCreepRangeAttackAbility(e);
                // damages_record[e.id] ={
                //     1:Math.max(val1,val2),
                //     3:val2
                // }
                this.setDamageRecord(
                    e,
                    {
                        1:Math.max(val1,val2),
                        3:val2
                    },
                    damages_record
                )
            }
        }

        return damages_record;
    }

    private setDamageRecord(creep:Creep,record:Record<number,number>,records:Record<string,Record<number,number>>)
    {
        records[creep.id] = record;
        this.updateDamageMap(creep,record);
        this.heal_max += BodySetup.GetBodyAbility(HEAL,"heal","heal",creep.body);
    }

    // 刷新Creep possible的伤害地图，用来寻路
    private updateDamageMap(creep:Creep,record:Record<number,number>)
    {

        let damagepos:RoomPosition[] = [];
        const update_MassDamage = (damage:Record<number, Record<number, number>>,pos:RoomPosition,creeppos:RoomPosition,val:number)=>
        {
            if(!damage[pos.x])
            {
                damage[pos.x]={};
            }
            let table=[1,0.4,0.1];
            let distance =  creeppos.distance(pos);
            let n =table[distance]?table[distance]:0.1;
            if(damage[pos.x][pos.y])
            {
                damage[pos.x][pos.y]+=n;
            }
            else
            {
                damage[pos.x][pos.y]=n;
            }
        }
        let n=0;
        if(record[3])
        {
            
            damagepos = PositionHelper.getFreeSpace( creep.pos,3+n);
            for(const e of damagepos)
            {
                update_MassDamage(this._hostileMassDamageMap,e,creep.pos,record[1]);
            }
        }
        else
        {
            damagepos = PositionHelper.getFreeSpace( creep.pos,1+n);
        }

        const update_posDamage = (damage:Record<number, Record<number, number>>,pos:RoomPosition,val:number)=>
        {
            if(!damage[pos.x])
            {
                damage[pos.x]={};
            }
            if(damage[pos.x][pos.y])
            {
                damage[pos.x][pos.y]+=val;
            }
            else
            {
                damage[pos.x][pos.y]=val;
            }
        }
        for(const e of damagepos)
        {
            update_posDamage(this._hostilePossibleDamageMap,e,record[1]);

        }
        this.damage_sum+=record[1];
    }
    get existFoe()
    {
        return this._exist_foe
    }
}

export class CacheHostilesTask<T = CacheDataHostiles<ICacheHostileCreep>> extends APollingTask<T>
{
    // roomName!:string;

   
    Update(...arg:any[]): void
    {
        // this.roomName = arg[0];
        const room = Game.rooms[this.code];
        if(room)
        {
             let  _exist_foe=false;
             let  _IsAggression=false;

            const HOSTILE_CREEPS =  room.find(FIND_HOSTILE_CREEPS );
            const cachehostile:ICacheHostileCreep[]=[];
            const attackableCreeps:Creep[]=[];  // 攻击性的爬
            const ubattackableCreeps:Creep[]=[];// 没有攻击性的爬
            const friendCreeps:ICacheHostileCreep[]=[];
            for(const item of HOSTILE_CREEPS)
            {
                
                const index= item.body.findIndex(bodyitem=>bodyitem.type==ATTACK || bodyitem.type==RANGED_ATTACK);
                let ret:ICacheHostileCreep=
                {
                    id:item.id,
                    pos:item.pos,
                    IsAggression:index>=0,
                    IsFoe:WhiteListManager.IsFoeCreep(item),
                    isFriend:WhiteListManager.IsFriendCreep(item),
                    hits:item.hits,
                    hitsMax:item.hitsMax,
                    isNPC:UtilsHelper.isNPC(item)

                }
                
                if(WhiteListManager.IsFriendCreep(item))
                {
                    friendCreeps.push(ret);
                    continue;
                }
                cachehostile.push(ret);
                if(ret.IsFoe)
                {
                    _exist_foe = true;
                    if(ret.IsAggression)
                    {
                        _IsAggression = true;
                    }
                }
                if(ret.IsAggression  )
                {
                    attackableCreeps.push(item);
                }
                else
                {
                    ubattackableCreeps.push(item);
                }


            }

            // if(Game.shard.name=="shard2")
            {
                // global.Log.Info(`[${this.code}]敌方单位 ${JSON.stringify(_.map(HOSTILE_CREEPS,e=>e.name))}`);
            }

            const cache = new CacheDataHostiles<ICacheHostileCreep>(cachehostile);
            cache._friendCache=friendCreeps;
            cache.updateHostileAbilityRecord(attackableCreeps,ubattackableCreeps);
            // Memory.Debug[`${this.code} 伤害系数`] = cache.hostileCreepAbility;
            (cache as  any)._exist_foe = {exist:_exist_foe,
                Aggression:_IsAggression};
            this.value=  cache as unknown as  T;
            if(cachehostile.length>0)
            {
                this.lastupdate = Game.time + 1;
            }
            else
            {
                this.lastupdate = Game.time + 11;
            }

        }
    }

}
